package com.powernode.lambda.parallelStream;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.stream.Collector;
import java.util.stream.Stream;

/**
 * 测试stream相关Api 并行流
 * 自己实现创建容器逻辑来观察并行流的运行逻辑
 * 大概逻辑为：
 * 并行流底层会生成多线程，每个线程各自创建一个容器，
 * 每个线程的各个容器添加一部分元素，接着每个线程的各个容器添加其他容器的元素，
 * 最后全部汇总到主线程中的容器中
 */
public class parallel01 {
    public static void main(String[] args) {

        /**
         * 1)数据量问题:数据量大(超过一百万)时才建议用并行流
         * 2) 线程会无限增加吗:跟cpU能处理的线程数相关
         * 3) 收尾的意义:转不可变集合、StringBuilder 转String ...
         * 4)是否线程安全:不会
         * 5)特性：
         *      默认收尾
         *      默认保证数据顺序
         *      默认不支持并发
         */

        //两个方法区别在于容器不同，以及特性不同
        Method1();
        //Method2();
    }

    private static void Method1() {
        Stream.of(1, 2, 3, 4)
                .parallel()
                .collect(Collector.of(
                        () -> {
                            System.out.printf("%-12s %s%n",simple(),"create");
                            return new ArrayList<Integer>();
                        },                                                 //如何创建容器
                        (list, x) -> {
                            List<Integer> old = new ArrayList<>(list);
                            list.add(x);
                            System.out.printf("%-12s %s.add(%d)=>%s%n",simple(), old, x, list);
                        },                                                 //如何向容器内添加数据
                        (list1, list2) -> {
                            List<Integer> old = new ArrayList<>(list1);
                            list1.addAll(list2);
                            System.out.printf("%-12s %s.add(%s)=>%s%n", simple(),old, list2, list1);
                            return list1;                                   //合并两个容器内的数据
                        },
                        list -> list                                       //收尾
//                        Collector.Characteristics.IDENTITY_FINISH,           //不需要收尾
//                        Collector.Characteristics.UNORDERED,           //不需要保证顺序
//                        Collector.Characteristics.CONCURRENT          //容器需要支持并发

                ));
    }

    private static void Method2() {
        Stream.of(1, 2, 3, 4)
                .parallel()
                .collect(Collector.of(
                        () -> {
                            System.out.printf("%-12s %s%n",simple(),"create");
                            return new Vector<Integer>();
                        },                                                 //如何创建容器
                        (list, x) -> {
                            List<Integer> old = new ArrayList<>(list);
                            list.add(x);
                            System.out.printf("%-12s %s.add(%d)=>%s%n",simple(), old, x, list);
                        },                                                 //如何向容器内添加数据
                        (list1, list2) -> {
                            List<Integer> old = new ArrayList<>(list1);
                            list1.addAll(list2);
                            System.out.printf("%-12s %s.add(%s)=>%s%n", simple(),old, list2, list1);
                            return list1;                                   //合并两个容器内的数据
                        },
                        list -> list,                                       //收尾
                        Collector.Characteristics.IDENTITY_FINISH,           //不需要收尾
                        Collector.Characteristics.UNORDERED,           //不需要保证顺序
                        Collector.Characteristics.CONCURRENT          //容器需要支持并发

                ));
    }

    public static String simple(){
        return Thread.currentThread().getName();
    }
}
